<?php
/*
  +----------------------------------------------------------------------+
  | CMDB.php                                                          |
  +----------------------------------------------------------------------+
  | Copyright (c) 2010 snda.com - Web Development Center                 |
  +----------------------------------------------------------------------+
  | commentdb engine                                                      |
  +----------------------------------------------------------------------+
  | Authors: Terry <leo9127@163.com>                                     |
  +----------------------------------------------------------------------+
*/
defined('DB_DEBUG')         || define('DB_DEBUG',   false);
defined('DB_TRACE')         || define('DB_TRACE',   false);
if (DB_TRACE) {
    defined('DB_TRACE_FILE')|| define('DB_TRACE_FILE', dirname(__FILE__).'/db.trace.'.date('mdh').'.log');
}
define('DB_DEFAULT_PAGE_SIZE', 25);
define('DB_DEVBUG_SERVER', true);

function &getCommentDataSource($const_db, $param = null, $need_hash = true) {
	$param = strtolower(trim($param));
	$driver      = 'mysql';
	$hash        = ($param && $need_hash) ? md5($param) : null;
  $user        = null;
  $pass        = null;
  $port        = 3306;
  $table       = null;
  $table_alias = null;
  switch ($const_db) {
  	case 'sender': //发送评论库
  	$decimal_hash2 = hexdec(substr($hash, 0, 2));
  	if (64 > $decimal_hash2) { $host = '10.129.128.14';
  	}else if(128 > $decimal_hash2){ $host = '10.129.128.14';
  	}else if(192 > $decimal_hash2){ $host = '10.129.128.14';
  	}else if(256 > $decimal_hash2){ $host = '10.129.128.14';
  	}
  	//$database = 'comment_00' .substr($hash, 0, 2);
    //$table = 'table_comment_sender_'.substr($hash, 0, 4);
    //$table_alias= 'table_comment_sender';
    $database = 'comment_sender';
    $table = 'table_comment_sender';
    $table_alias= 'table_comment_sender';
    $user = 'root';
    $pass = '123qwe';
    break;
    case 'receiver': //接收评论
    $decimal_hash2 = hexdec(substr($hash, 0, 2));
  	if (64 > $decimal_hash2) { $host = '10.129.128.14';
  	}else if(128 > $decimal_hash2){ $host = '10.129.128.14';
  	}else if(192 > $decimal_hash2){ $host = '10.129.128.14';
  	}else if(256 > $decimal_hash2){ $host = '10.129.128.14';
  	}
  	/*$database = 'comment_00' .substr($hash, 0, 2);
    $table = 'table_comment_receiver_'.substr($hash, 0, 4);
    $table_alias= 'table_comment_receiver';*/
    $database = 'comment_receiver';
    $table = 'table_comment_receiver';
    $table_alias= 'table_comment_receiver';
    $user = 'root';
    $pass = '123qwe';
    break;
    case 'module': //对象评论
    $need_hash || $hash = $param;
    $decimal_hash2 = hexdec(substr($hash, 0, 2));
  	if (64 > $decimal_hash2) { $host = '10.129.128.14';
  	}else if(128 > $decimal_hash2){ $host = '10.129.128.14';
  	}else if(192 > $decimal_hash2){ $host = '10.129.128.14';
  	}else if(256 > $decimal_hash2){ $host = '10.129.128.14';
  	}
  	/*$database = 'comment_reply_00'.substr($hash, 0, 2);
    $table = 'table_comment_reply_'.substr($hash, 0, 4);
    $table_alias= 'table_comment_reply';*/
    $database = 'comment_module';
    $table = 'table_comment_module';
    $table_alias= 'table_comment_module';
    $user = 'root';
    $pass = '123qwe';
    break;
    case 'visitors': //谁来看过我访问信息
    $host = '10.129.128.14';
    $database = 'visitors';
    $table = 'visitors_table';
    $table_alias= 'visitors_table';
    $user = 'root';
    $pass = '123qwe';
    break;
    case 'browse': //我去看过谁访问信息
    $host = '10.129.128.14';
    $database = 'visitors';
    $table = 'browse_table';
    $table_alias= 'browse_table';
    $user = 'root';
    $pass = '123qwe';
    break;
    default :
    $ret = array();
    return $ret;
  }
  $ret = array('driver'=>$driver,
  							'host' => $host,
  							'port' => ($port ? "{$port}" : ''),
  							'user' => is_null($user) ? "root" : $user,
                'pass' => is_null($pass) ? "123qwe" : $pass,
                'database'      => $database,
                'table'         => $table,
                'table_alias'   => $table_alias);
  return $ret;
}

class CMDB{
	private static $dsn;
  private static $tmp_dsn;

  protected static $db_link;
  protected static $last_error;
  protected static $trace;
  protected static $page;
  protected static $affected_rows  = 0;
  
  static function trace($s) {
  	if (DB_DEBUG) { self::$trace[] = $s; }
  }
  
  static function close() {
  	if (is_resource(self::$db_link)) { mysql_close(self::$db_link); }
  }
  
  static function escape($data, $data_is_array = false) {
  	if($data_is_array){
  		$tmp = array();
  		foreach ($data as $k => $v){
  			$tmp[$k] = htmlspecialchars(html_entity_decode($v,ENT_QUOTES),ENT_QUOTES);
  		}
  		return $tmp;
  	}
  	return htmlspecialchars(html_entity_decode($data,ENT_QUOTES),ENT_QUOTES);
  }
  
  static function dsn($const_db, $hash = null, $need_hash = true){
  	self::trace('dsn('.$const_db.','.$hash.')');
  	if (empty($const_db)){return;}
  	if (!(self::$tmp_dsn = getCommentDataSource($const_db, $hash, $need_hash))){
  		return self::$dsn = null;
  	}
  	if(self::$dsn['host'] == self::$tmp_dsn['host']){
  		if(self::$dsn['database'] != self::$tmp_dsn['database'] && is_resource(self::$db_link)){
  			self::trace('USE'.self::$tmp_dsn['database']);
   			if (!mysql_select_db(self::$tmp_dsn['database'], self::$db_link)){
  				self::setError(mysql_error(self::$db_link));
  			}
  		}
  	}else{
  		self::close();
  	}
  	self::$dsn = self::$tmp_dsn;
  }
  
  static function setError($msg) {
  	self::$last_error = $msg;
  	self::trace($msg);
  }
  
  static function &lastError(){
  	return self::$last_error;
  }
  
  static function affectedRows() {
  	return self::$affected_rows;
  }
  
  //连接DB
  static function connect(){
   	if(is_resource(self::$db_link)){return;}
   	$feedback = '<span style="display:none;">Server busy.</span>';
  	if(empty(self::$dsn)){
  		self::setError('Lost data source');
  		self::printTrace();
  		echo $feedback;
  		return false;
  	}
  	if(1 < DB_DEBUG){
  		$temp_start = microtime(1);
  		self::trace('Connect DB:'.self::$dsn['host'].' ('.self::$dsn['database'].')');
  	}
  	self::$db_link = mysql_connect(self::$dsn['host'], self::$dsn['user'], self::$dsn['pass']);
   	if (!self::$db_link){
  		echo $feedback;
  		self::trace(mysql_error(self::$db_link));
  		self::printTrace();
  		return false;
  	}
  	
  	if(1 < DB_DEBUG){
  		self::trace('Connect consume: '.(microtime(1) - $temp_start));
  	}
  	
  	 if(isset(self::$dsn['database'])){
  	 	 if(!mysql_select_db(self::$dsn['database'], self::$db_link)){
  	 	 	self::setError(mysql_error(self::$db_link));
  	 	}
  	}
  }
  
  //解析SQL语句
  static protected function &execute($sql, $query_with_page = false){
  	is_resource(self::$db_link) || self::connect();
  	$result = false;
  	if(!is_resource(self::$db_link)){
  		return $result;
  	}
  	self::$last_error = null;
  	self::$affected_rows = 0;
  	if(!empty(self::$dsn['table_alias'])){
  		if (2 < DB_DEBUG){
  			self::trace($sql);
  		}
  		$sql = preg_replace(
  						'/(from|update|insert|insert into|delete|delete from)\s+'.self::$dsn['table_alias'].' ?/is',
  						' \1 '.self::$dsn['table'].' ',
  						$sql,1);
  	}
  	//echo $sql;
  	if ($query_with_page){
  		if(1 > self::$page['total_rows']){
  			if (false == ($count_sql = stristr($sql, ' from '))){
  				self::setError("[E] Parse SQL fail {$sql}");
  				return $result;
  			}
  			// filter ORDER BY xxx, keep LIMIT xx
  			$pos_order = stripos($count_sql, "order by");
  			$pos_limit = stripos(substr($count_sql, $pos_order), ' limit ');
  			$count_sql = substr($count_sql, 0, $pos_order);
  			if ($pos_limit) {
  				$count_sql .= substr($count_sql, $pos_order + $pos_limit);
  			}
  			$count_sql = "SELECT COUNT(1) ".$count_sql;
  			if(2 < DB_DEBUG){
  				$query_time = microtime(1);
          $tmp_result = mysql_query($count_sql, self::$db_link);
          $query_time = microtime(1) - $query_time;
        }else{
        	$tmp_result = mysql_query($count_sql, self::$db_link);
        }
        if(mysql_errno(self::$db_link)) {
        	self::trace($count_sql);
        	self::setError(mysql_error(self::$db_link));
          return $result;
        }
        $tmp_result= mysql_fetch_row($tmp_result);
        self::$page['total_rows']  = $tmp_result[0];
        if (2 < DB_DEBUG) {
        	self::trace($count_sql);
        	self::trace(sprintf("%s rows in set (%.5f sec)", self::$page['total_rows'], $query_time));
        }
      }
      self::$page['total_pages'] = ceil(self::$page['total_rows'] / self::$page['size']);
      if(self::$page['total_pages'] < self::$page['current']){
      	self::$page['current'] = self::$page['total_pages'];
      }
      if(2 > intval(self::$page['current'])){
      	self::$page['current'] = 1;
      }
      $sql .= ' LIMIT '.((self::$page['current'] - 1) * self::$page['size']).','.self::$page['size'];
    }
    
    if (DB_DEBUG){
    	self::trace($sql);
    	$query_time = microtime(1);
    	$result     = mysql_query($sql, self::$db_link);
    	$query_time = microtime(1) - $query_time;
    	if (mysql_errno(self::$db_link)) {
    		self::setError(mysql_error(self::$db_link));
    		self::printTrace();// for test
    	}else{
    		self::$affected_rows = is_resource($result)
                               ? mysql_num_rows($result)
                               : mysql_affected_rows(self::$db_link);
        self::trace(sprintf("%s rows in set (%.5f sec)", self::$affected_rows, $query_time));
      }
    }else{
    	$result = mysql_query($sql, self::$db_link);
    	$errno  = mysql_errno(self::$db_link);
    	if($errno){
    		self::setError(mysql_error(self::$db_link));
    		if (DB_ERROR_LOG && (1062 != $errno)) { // ignore error [Duplicate entry 'xxx' for key 1]
    			error_log($sql."\n".self::$last_error."\n", 3, DB_TRACE_FILE);
    		}
    	}else{
    		self::$affected_rows = is_resource($result)
    														? mysql_num_rows($result)
    														: mysql_affected_rows(self::$db_link);
     }
   }
   return $result;
 	}
 	
 	//从结果集中取得一行作为对象
 	static function getRecord($sql){
 		if($res = self::query($sql)){
 			return mysql_fetch_object($res, 'Record');
 		}
 	}
 	
 	//从结果集中取得一行作为枚举数组
 	static function getField($sql){
 		if($res = self::query($sql)){
 			$ret = mysql_fetch_row($res);
 			return $ret[0];
 		}
 	}
 	
 	//从结果集中取得一行作为关联数组
 	static function getRow($sql) {
 		if($res = self::execute($sql)){
 			return mysql_fetch_assoc($res);
 		}
 	}
 	
 	static function getRows($sql) {
 		if ($res = self::query($sql)) {
 			$ret = array();
 			while($row = mysql_fetch_assoc($res)){
 				$ret[] = $row;
 			}
 		 return $ret;
 		}
 	}
 	
 	static function getPage($sql,$current_page = 1,$total_rows = 0, $page_size = DB_DEFAULT_PAGE_SIZE){
 		self::$page['size']         = (int)$page_size;
 		self::$page['current']      = (int)$current_page;
 		self::$page['total_rows']   = (int)$total_rows;
 		self::$page['total_pages']  = 1;
 		$ret = false;
 		$res = self::execute($sql, true);
 		if(self::$affected_rows){
 			$ret = array();
 			while($row = mysql_fetch_assoc($res)){
 				$ret["rows"][] = $row;
 			}
 			mysql_free_result($res);
 			$ret["page"] = self::$page;
 		}
 		return $ret;
 	}
 	
 	static function &query($sql) {
 		return self::execute($sql, false);
 	}
 	
 	static function insert($table, $data){
 		if(empty($data)){
 			$this->trace('insert '.$table.' empty data');
 			return;
 		}
 		while(list($key,$val) = each($data)){
 			$field .= "$key,";
 			$value .= "'$val',";
 		}
  	$field = substr($field, 0, -1);
  	$value = substr($value, 0, -1);
  	$sql = "INSERT INTO $table ($field) VALUES ($value)";
 		
 		//$fields = null;
 		//foreach ($data as $k => $v) {
 			//$fields .= " '".$k."' = '".$v."',";
 		//}
 		//$fields = rtrim($fields,',');
 		return $sql ? self::execute($sql) : false;
 	}
 	
 	static function insertId(){
 		return mysql_insert_id(self::$db_link);
 	}
 	
 	static function update($table, $data, $where, $limit = 1) {
 		if(empty($this->_fields)) return;
 		$fields = null;
 		foreach ($data as $k => $v) {
 			$fields .= " `".$k."` = ".$v.",";
 		}
 		$fields = rtrim($fields,',');
 		$limit  = intval($limit);
 		return $fields ? self::execute("UPDATE $table SET $fields WHERE $where LIMIT $limit") : false;
 	}
 	
 	static function updates($table, $data, $where) {
 		if(empty($this->_fields)) return;
 		$fields = null;
 		foreach ($data as $k => $v) {
 			$fields .= " `".$k."` = ".$v.",";
 		}
 		$fields = rtrim($fields,',');
 		$limit  = intval($limit);
 		return $fields ? self::execute("UPDATE $table SET $fields WHERE $where") : false;
 	}
 	
 	static function printTrace($return = false){
 		if (DB_DEBUG) {
 			return print_r(self::$trace, $return);
 		}
 	}
}
?>